import {VirtualLoopData} from '../../models/svgdata';
import {Graph, Markup, Node} from '@antv/x6';
import {drawConfigType, drawPropsType, BaseDrawConfig} from '../types/draw-config.type';
import {OutputList, InputList} from '../../models/svgdata'
import '@svgdotjs/svg.panzoom.js';


interface sizeType {
  width: number,
  height: number
}

const drawDefaultConfig: drawConfigType = {
  baseDrawConfig: {
    moduleDistance: 700,
    font: {
      small: 8,
      normal: 11,
    },
    color: {
      primary: '#00367a',
      moduleBorderColor: '#25ccf7',
      accent: '#25ccf7',
      text: '#ffffff',
      dashedLine: '#000000',
    }
  },
  loopBranchConfig: {
    lineColor: '#25ccf7',
    textColor: '#ffffff',
    textSize: 8,
    lineDistance: 700,
  }
}


export function softStrapShapeRegister(baseDrawConfig: BaseDrawConfig = drawDefaultConfig.baseDrawConfig){
  Graph.registerNode('softStrap-shape', {
    inherit: 'rect',
    width: 110,
    height: 24,
    markup: [
      {
        tagName: 'g',
        selector: 'softStrapGraph',
        children: [
          { tagName: 'rect', selector: 'midGraph' },
          { tagName: 'circle', selector: 'leftGraph' },
          { tagName: 'circle', selector: 'rightGraph' },
        ],
      },
      { tagName: 'text', selector: 'softStrapText' },
    ],
    attrs: {
      softStrapGraph: {
        refX: '40%',
        refY: '-8%',
      },
      midGraph: {
        width: 24,
        height: 8,
        rx: 4,
        ry: 4,
        fill: '#bdf4f1',
        strokeWidth: 0,
      },
      leftGraph: {
        r: 4,
        cx: 4,
        cy: 4,
        fill: 'white',
        strokeWidth: 0,
      },
      rightGraph: {
        r: 4,
        cx: 20,
        cy: 4,
        fill: 'white',
        strokeWidth: 0,
      },
      softStrapText: {
        text: '',
        fill: baseDrawConfig.color.text,
        fontSize: baseDrawConfig.font.small,
        textAnchor: 'middle',
      },
    },
  }, true)
}

export function  customShapeRegister(baseDrawConfig: BaseDrawConfig = drawDefaultConfig.baseDrawConfig){
  Graph.registerNode('custom-shape', {
    inherit: 'rect',
    width: 860,
    height: 270,
    markup: [
      { tagName: 'circle', selector: 'startPoint' },
      { tagName: 'path', selector: 'arrowHead' },
      { tagName: 'line', selector: 'mainLine' },
      { tagName: 'text', selector: 'leftText' },
      { tagName: 'text', selector: 'rightText' },
      {
        tagName: 'g', selector: 'changeLabel', children: [
          { tagName: 'rect', selector: 'changeBackground' },
          { tagName: 'text', selector: 'changeText' }
        ]
      },
      {
        tagName: 'g', selector: 'endGroup', children: [
          { tagName: 'rect', selector: 'endPoint' },
          { tagName: 'text', selector: 'endLabel' }
        ]
      },
      { tagName: 'g', selector: 'loopBranch' },
    ],
    attrs: {
      startPoint: {
        r: baseDrawConfig.font.small,
        fill: baseDrawConfig.color.accent,
        strokeWidth: 0,
      },
      leftText: {
        text: '',
        fill: baseDrawConfig.color.text,
        fontSize: baseDrawConfig.font.small,
        x: 110,
        y: -5,
        refX: null,
        refY: null,
        textAnchor: 'start',
      },
      arrowHead: {
        d: `M400 0 l-16 -8 l8 8 l-8 8 Z`,
        selector: 'arrowHead',
        fill: baseDrawConfig.color.accent,
        strokeWidth: 0,
        cursor: 'pointer',
        'pointer-events': 'visiblePainted'
      },
      rightText: {
        text: '',
        fill: baseDrawConfig.color.text,
        fontSize: baseDrawConfig.font.small,
        x: 632,
        y: -5,
        refX: null,
        refY: null,
        textAnchor: 'start',
      },
      endPoint: {
        width: 60,
        height: 20,
        fill: baseDrawConfig.color.accent,
        x: 780,
        y: -10,
        strokeWidth: 0,
      },
      endLabel: {
        text: 'GOOSE 0x032C',
        // fill: '#fff',
        fontSize: baseDrawConfig.font.small,
        ref: 'endPoint',
        refX: 0.5,
        refY: 0.5,
      },
      changeBackground: {
        width: 20,
        height: 10,
        fill: '#0985d9',
        x: 20,
        y: -12,
        strokeWidth: 0,
      },
      changeText: {
        text: '展开',
        fontSize: baseDrawConfig.font.small,
        ref: 'changeBackground',
        refX: 0.5,
        refY: 0.5,
      },
      mainLine: {
        stroke: baseDrawConfig.color.accent,
        strokeWidth: 2,
        x1: 0,
        y1: 0,
        x2: 780,
        y2: 0,
      },
      loopBranch: {
        visibility: 'visible',
      }
    },
  }, true)
}

export function heightCompute(data: VirtualLoopData): number {
  let predictHeight = 100
  data.connectionData[0].outputList.forEach(output => {
    output.enaTerminalList.forEach(enTerminal => {
      predictHeight += 20 * enTerminal.terminalList.length
    })
    predictHeight += 60
  })
  data.connectionData[0].inputList.forEach(input => {
    input.enaTerminalList.forEach(enTerminal => {
      predictHeight += 20 * enTerminal.terminalList.length
    })
    predictHeight += 60
  })
  predictHeight -= 20
  return predictHeight
}

export function render(graph: Graph, data: VirtualLoopData, canvasSize: sizeType, moduleSize: sizeType, shapeSoftStrapMap: Map<string, string[]>, loopBranchVisibilityMap: Map<string, Boolean>,  drawPropsType: drawPropsType) {
  const drawConfig = drawPropsType.drawConfig || drawDefaultConfig
  const canvasNode = graph.addNode({
    id: 'sub-canvas',
    width: canvasSize.width,
    height: canvasSize.height,
    selector: 'sub-canvas',
    label: '',
    shape: 'rect',
    // draggable: true,
    attrs: {
      body: {
        fill: '#070a0a',
      }
    }
  });

  const moduleNode = graph.addNode({
    id: 'module-rect',
    width: moduleSize.width+700,
    height: moduleSize.height,
    label: '',
    shape: 'rect',
    draggable: false,
    attrs: {
      body: {
        fill: 'none',
        strokeWidth: 0,
      }
    }
  });

  let elementHeight = 35  //预估模块元素渲染高度,从上向下依次绘制

  const leftGroup = graph.addNode({
    id: 'leftGroup',
    shape: 'rect',
    x: 0,
    y: 0,
    width: drawPropsType.moduleSize.width,
    height: drawPropsType.moduleSize.height,
    draggable: false,
    // label: data.connectionData[0].noCentreIed.name,
    attrs: {
      body: {
        fill: drawConfig.baseDrawConfig.color.primary,
        stroke: drawConfig.baseDrawConfig.color.moduleBorderColor,
        strokeWidth: 0.5
      },
      label: {
        text: `${data.connectionData[0].noCentreIed.name}\n${splitTextByLineLength(data.connectionData[0].noCentreIed.desc)}`,
        fill: drawConfig.baseDrawConfig.color.text,
        fontSize: drawConfig.baseDrawConfig.font.normal,
        fontFamily: 'Arial, sans-serif',
        textAnchor: 'middle',
        refX: `50%`,
        refY: `${elementHeight}px`,
        ref: 'rect',
        textVerticalAnchor: 'middle',
        lineHeight: 14,
      }
    },
  });


  const dashedBox = graph.addNode({
    id: 'dashedBox',
    shape: 'rect',
    x: drawConfig.baseDrawConfig.moduleDistance - 5,
    y: -5,
    width: drawPropsType.moduleSize.width + 10,
    height: drawPropsType.moduleSize.height + 10,
    draggable: false,
    attrs: {
      body: {
        fill: 'none',
        stroke: drawConfig.baseDrawConfig.color.moduleBorderColor,
        strokeWidth: 0.5,
        strokeDasharray: '5 5'
      },
    }
  })



  const rightGroup = graph.addNode({
    id: 'rightGroup',
    shape: 'rect',
    x: drawConfig.baseDrawConfig.moduleDistance,
    y: 0,
    width: drawPropsType.moduleSize.width,
    height: drawPropsType.moduleSize.height,
    draggable: false,
    attrs: {
      body: {
        fill: drawConfig.baseDrawConfig.color.primary,
        stroke: drawConfig.baseDrawConfig.color.moduleBorderColor,
        strokeWidth: 0.5
      },
      label: {
        text: `${data.connectionData[0].noCentreIed.name}\n${splitTextByLineLength(data.connectionData[0].noCentreIed.desc)}`,
        fill: drawConfig.baseDrawConfig.color.text,
        fontSize: drawConfig.baseDrawConfig.font.normal,
        fontFamily: 'Arial, sans-serif',
        textAnchor: 'middle',
        refX: `50%`,
        refY: `${elementHeight}px`,
        ref: 'rect',
        textVerticalAnchor: 'middle',
        lineHeight: 14,
      }
    },
  });

  elementHeight += 60

  for(let outputItem of data.connectionData[0].outputList){
    const nodeId = `lineCroup-${outputItem.appid16}`;
    const lineCroup = graph.addNode({
      id: nodeId,
      shape: 'custom-shape',
      draggable: false,
      x: 70,
      y: elementHeight,
      attrs: {
        leftText: {
          text: outputItem.outputPort,
        },
        rightText: {
          text: outputItem.inputPort,
        },
        arrowHead: {
          transform: 'rotate(180, 350, 0)'
        },
      }
    })

    loopBranchVisibilityMap.set(nodeId, true);
    moduleNode.addChild(lineCroup)
    elementHeight += updateBranches(graph, lineCroup, elementHeight, outputItem, {x: 750, y: 0}, shapeSoftStrapMap) + 40
  }

  for(let inputItem of data.connectionData[0].inputList){
    const nodeId = `lineCroup-${inputItem.appid16}`;
    const lineCroup = graph.addNode({
      id: nodeId,
      shape: 'custom-shape',
      draggable: false,
      x: 70,
      y: elementHeight,
      attrs: {
        startPoint: {
          cx: 780,
          cy: 0,
        },
        endPoint: {
          x: -60,
          y: -10,
        },
        leftText: {
          text: inputItem.outputPort,
        },
        rightText: {
          text: inputItem.inputPort,
        },
      }
    })

    // 初始化显示状态为true
    loopBranchVisibilityMap.set(nodeId, true);

    moduleNode.addChild(lineCroup)

    elementHeight += updateBranches(graph, lineCroup, elementHeight, inputItem, {x: 750, y: 0}, shapeSoftStrapMap) + 40
    // this.updateBranches(lineCroup, inputItem, {x: 750, y: 300})
  }

  canvasNode.addChild(moduleNode)
  moduleNode.addChild(leftGroup)
  moduleNode.addChild(rightGroup)
  moduleNode.addChild(dashedBox)

  const offsetX = (canvasNode.size().width - moduleNode.size().width) / 2
  const offsetY = (canvasNode.size().height - moduleNode.size().height) / 2
  moduleNode.translate(offsetX, offsetY)

  const container = graph.container as HTMLElement;
  const canvasBBox = canvasNode.getBBox();
  const offsetX1 = (container.clientWidth - canvasBBox.width) / 2
  const offsetY1 = (container.clientHeight - canvasBBox.height) / 2
  canvasNode.translate(offsetX1, offsetY1);

  // // 获取节点对应的 SVG 元素
  // const nodeView = graph.findViewByCell(canvasNode)
  // const nodeElement = nodeView!.container
  // const pz = panzoom(nodeElement, {
  //   zoomDoubleClickSpeed: 1, // 双击不缩放
  //   maxZoom: 3,
  //   minZoom: 0.5
  // })
}

export function splitTextByLineLength(text: string, maxCharsPerLine: number = 19) {
  if (!text || maxCharsPerLine <= 0) return text || '';
  const lines = [];
  let start = 0;
  const len = text.length;
  while (start < len) {
    let slice = text.slice(start, start + maxCharsPerLine);
    if (start + maxCharsPerLine < len && text[start + maxCharsPerLine] !== ' ' && slice.includes(' ')) {
      const lastSpaceIdx = slice.lastIndexOf(' ');
      if (lastSpaceIdx > 0) {
        slice = slice.slice(0, lastSpaceIdx);
      }
    }
    lines.push(slice.trim());
    start += slice.length;
  }
  return lines.join('\n');
}

export function addLoopBranchLine(pathData: string){
  return {
    tagName: 'path',
    attrs: {
      d: pathData,
      fill: 'none',
      stroke: '#25ccf7',
      strokeWidth: 1
    }
  };
}

export function addLoopBranchText(selector: string, textContent: string, point: {x: number, y: number}, textAnchor: 'start' | 'end' ){
  const textElement: Markup.JSONMarkup = {
    tagName: "text",
    selector: selector,
    textContent: textContent,
    attrs: {
      x: point.x,
      y: point.y,
    }
  };

  const attrs = {
    fontSize: 8,
    fill: '#fff',
    pointerEvents: 'none',
    refX: null,
    refY: null,
    textAnchor: textAnchor,
  };

  return { textElement, attrs: { [selector]: attrs }};
}

export function updateBranches(graph: Graph, node: Node, elementHeight: number, messageContent: InputList | OutputList, rightPoint: {x: number, y: number}, shapeSoftStrapMap?: Map<string, string[]>) {

  const branchElements: Markup.JSONMarkup[] = []
  let branchAttrs: Record<string, any> = {};
  const id = messageContent.appid16
  let branchTextIndex = 0; // 用于唯一selector编号

  let height = 20;
  for (let item of messageContent.enaTerminalList) {
    let pathData = ''
    const hasSwitch = !!item.ena;
    if(item.terminalList.length > 1) {
      pathData += `M${rightPoint.x} ${rightPoint.y} l0 ${height + 20 * (item.terminalList.length - 1)/2} l-152 0`;
      const endX =  rightPoint.x  - 152;
      const endY = rightPoint.y + height+ 20 * (item.terminalList.length - 1)/2;
      if (hasSwitch) {
        node.addChild(renderSoftStrap(graph, 706, height + 20 * (item.terminalList.length - 1)/2 + elementHeight, item.ena.outputEnaDesc, node.id, shapeSoftStrapMap))
      }
      for (let branch of item.terminalList) {
        pathData += `M${endX} ${endY} l0 ${height - endY} l-572 0 l0 -20`;
        let selector = `${id}-${branchTextIndex}`;
        const leftData = addLoopBranchText(selector, hasSwitch ? item.terminalList[0].inputDesc : item.terminalList[0].outputDesc, {x: 180, y: height + rightPoint.y - 4}, 'start')
        branchElements.push(leftData.textElement);
        branchAttrs = { ...branchAttrs, ...leftData.attrs };
        branchTextIndex++;

        selector = `${id}-${branchTextIndex}`;
        const rightData = addLoopBranchText(selector, hasSwitch ? item.terminalList[0].outputDesc : item.terminalList[0].inputDesc, {x: 580, y: height + rightPoint.y - 4}, 'end')
        branchElements.push(rightData.textElement);
        branchAttrs = { ...branchAttrs, ...rightData.attrs };

        branchTextIndex++;
        height += 20;
      }
    }else if(item.terminalList.length === 1) {
      if(hasSwitch){
        node.addChild(renderSoftStrap(graph, 706, height + 20 * (item.terminalList.length - 1)/2 + elementHeight, item.ena.outputEnaDesc, node.id, shapeSoftStrapMap))
      }
      pathData += `M${rightPoint.x} ${rightPoint.y} l0 ${height} l-724 0 l0 -20`;
      let selector = `${id}-branchText${branchTextIndex}`;
      const leftData = addLoopBranchText(selector, hasSwitch ? item.terminalList[0].inputDesc : item.terminalList[0].outputDesc, {x: 180, y: height + rightPoint.y - 4}, 'start')
      branchElements.push(leftData.textElement);
      branchAttrs = { ...branchAttrs, ...leftData.attrs };
      branchTextIndex++;
      selector = `${id}-${branchTextIndex}`;

      const rightData = addLoopBranchText(selector, hasSwitch ? item.terminalList[0].outputDesc : item.terminalList[0].inputDesc, {x: 580, y: height + rightPoint.y - 4}, 'end')
      branchElements.push(rightData.textElement);
      branchAttrs = { ...branchAttrs, ...rightData.attrs };
      branchTextIndex++;
      height += 20;
    }
    branchElements.push(addLoopBranchLine(pathData));
  }
  // 更新 loopBranch
  node.setMarkup([
    { tagName: 'circle', selector: 'startPoint' },
    { tagName: 'line', selector: 'mainLine' },
    { tagName: 'path', selector: 'arrowHead' },
    { tagName: 'text', selector: 'leftText' },
    { tagName: 'text', selector: 'rightText' },
    {
      tagName: 'g', selector: 'changeLabel', children: [
        { tagName: 'rect', selector: 'changeBackground' },
        { tagName: 'text', selector: 'changeText' }
      ]
    },
    {
      tagName: 'g', selector: 'endGroup', children: [
        { tagName: 'rect', selector: 'endPoint' },
        { tagName: 'text', selector: 'endLabel' }
      ]
    },
    {
      tagName: 'g',
      selector: 'loopBranch',
      children: branchElements,
    },
  ], { silent: true })

  node.setAttrs(branchAttrs);

  return height
}

export function renderSoftStrap(graph: Graph, x: number, y: number, desc: string, parentNodeId?: string, shapeSoftStrapMap?: Map<string, string[]>) {
  const softStrapId = `softStrap${y}`;
  const sortStrap = graph.addNode({
    id: softStrapId,
    shape: 'softStrap-shape',
    draggable: false,
    x: x,
    y: y-2,
  })
  sortStrap.attr('softStrapText/text', desc);

  if (parentNodeId && shapeSoftStrapMap) {
    if (!shapeSoftStrapMap.has(parentNodeId)) {
      shapeSoftStrapMap.set(parentNodeId, []);
    }
    shapeSoftStrapMap.get(parentNodeId)!.push(softStrapId);
  }

  return sortStrap
}
